# coding: utf-8

import os
import datetime
import time
import logging

from geventwebsocket import WebSocketError
from sqlalchemy import create_engine
from sqlalchemy.sql import text

from ..import sockets
from app.auth.constant import AgentState
from app.ccws.constant import QueueState, CallState

DB_USER = os.environ.get('DB_USER') or 'root'
DB_PWD = os.environ.get('DB_PWD') or ''
DB_HOST = os.environ.get('DB_HOST') or 'localhost'
DB_NAME = os.environ.get('DB_NAME') or 'wph_www_prod'

select_waiting_outbound_sql = text("""
    select
        id,local_call_id,mobile,call_state
    from
        outbound_records
    where
        queue_state = :queue_state and
        schedule_time <= :schedule_time
    order by
        call_weight asc,
        schedule_time asc,
        created_at asc
    limit :get_record_num;
""")

select_prior_outbound_sql = text("""
    select
        id,local_call_id,mobile,call_state
    from
        outbound_records
    where
        queue_state = :queue_state and
        schedule_time <= :schedule_time and
        call_weight = 100
    order by
        created_at asc
    limit :get_record_num;
""")

update_waiting_outbound_sql = text("""
    update
        outbound_records
    set
        queue_state = :queue_state
    where
        id = :id;
""")

get_onlie_agent_num_sql = text("""
    select
        count(*)
    from
        admin
    where
        agent_state=:agent_state and agent_login_time>:valid_login_date;
""")

def test_job(a, b):
    current_hour = datetime.datetime.now().hour
    if current_hour<9 or current_hour>15:
        return
    print(str(a) + ' ' + str(b))


def outbound_job():
    """
    查询外呼记录，并根据队列情况发送消息至ws执行外呼
    """
    current_app = sockets.app
    with current_app.app_context():
        if not current_app.observers:
            logging.error('There is not any websocket!!!')

        current_hour = datetime.datetime.now().hour
        if (9 <= current_hour < 21):

            wph_engine = create_engine(
                'mysql+pymysql://%s:%s@%s/%s?charset=utf8' % (
                    DB_USER, DB_PWD, DB_HOST, DB_NAME
                ),
                encoding='utf-8'
            )

            wph_conn = wph_engine.connect()

            # 取12小时内签入的座席数目
            valid_login_date = datetime.datetime.now() - \
                datetime.timedelta(hours=12)

            online_agent_num = wph_conn.execute(
                get_onlie_agent_num_sql,
                agent_state=AgentState.LOGIN.value,
                valid_login_date=valid_login_date,
            ).fetchall()[0][0]
            logging.error('current agent number:%s' %online_agent_num)

            pending_handle_records = []
            if online_agent_num > 1:
                get_record_num = online_agent_num \
                    - len(current_app.outbound_dict)
                if get_record_num > 0:
                    pending_handle_records = wph_conn.execute(
                        select_waiting_outbound_sql,
                        queue_state=QueueState.WAITING.value,
                        schedule_time=datetime.datetime.now(),
                        get_record_num=get_record_num,
                    )
            else:
                # 如果没有外呼任务，且少于两个座席在线，优先执行权重为100的任务
                if not current_app.outbound_dict:
                    pending_handle_records = wph_conn.execute(
                        select_prior_outbound_sql,
                        queue_state=QueueState.WAITING.value,
                        schedule_time=datetime.datetime.now(),
                        get_record_num=1,
                    )

            for i in pending_handle_records:
                current_app.outbound_dict[i.local_call_id] = {
                    'mobile': i.mobile,
                    'call_state': CallState.WAITING.value,
                    'ts': int(time.time()),
                }
                wph_conn.execute(
                    update_waiting_outbound_sql,
                    queue_state=QueueState.HANDLING.value,
                    id=i.id,
                )
            wph_conn.close()

        if current_app.outbound_dict and (9 <= current_hour < 21):
            # 有外呼任务，且在服务时间
            for local_call_id in current_app.outbound_dict:
                tmp_record = current_app.outbound_dict[local_call_id]
                if tmp_record['call_state'] == CallState.WAITING.value:

                    message = '{"msgType":"CCX_Call", "id":"%s", "called":"%s"}' % (
                        local_call_id, tmp_record['mobile'],)
                    ws_keys = list(current_app.observers.keys())
                    for key in ws_keys:
                        socket = current_app.observers.get(key)
                        if not socket.closed:
                            try:
                                socket.send(message)
                                logging.error('send message:%s' %message)
                                logging.error('{mobile} had joined into outbound queue'.format(mobile=tmp_record['mobile']))
                            except WebSocketError:
                                #del current_app.observers[key]
                                logging.error('%s has errors' %socket)
                        else:
                            del current_app.observers[key]
                            logging.error('%s is closed' %socket)

        # 发送心跳
        ws_keys = list(current_app.observers.keys())
        # id为时间戳，微秒为单位，兼容Java的时间戳
        message = '{"msgType":"Heartbeat","callId":"","id":"%s","called":""}' % str(int(time.time()*1000))
        for key in ws_keys:
            socket = current_app.observers.get(key)
            if not socket.closed:
                try:
                    socket.send(message)
                    logging.error('send message:%s' %message)
                except WebSocketError:
                    #del current_app.observers[key]
                    logging.error('%s has errors' %socket)
            else:
                del current_app.observers[key]
                logging.error('%s is closed' %socket)

        # 防止因为ws消息丢失，导致 outbound_dict 堵塞。超过300秒的将被del
        ts = int(time.time())
        local_call_id_keys = list(current_app.outbound_dict.keys())
        for local_call_id in local_call_id_keys:
            tmp_r = current_app.outbound_dict[local_call_id]
            if ts - tmp_r['ts'] >= 300 and \
                tmp_r['call_state'] != CallState.WAITING.value:
                del current_app.outbound_dict[local_call_id]


